package com.shield;

import com.shield.framework.config.ShieldConstant;
import com.shield.framework.config.ShieldSecurityConfig;
import com.shield.framework.config.ShieldSecurityProperties;
import com.shield.framework.jpa.entity.ShieldToken;
import com.shield.framework.jpa.repository.ShieldTokenRepository;
import com.shield.framework.security.auth.ShieldAuthHandler;
import com.shield.framework.security.authentication.ShieldAuthenticationTokenFilter;
import com.shield.framework.security.service.ShieldUserDetailsService;
import com.shield.framework.security.store.db.ShieldDbTokenStore;
import com.shield.framework.security.store.redis.ShieldRedisTokenStore;
import com.shield.framework.security.token.ShieldTokenService;
import com.shield.framework.security.token.ShieldTokenStore;
import com.shield.framework.security.token.jwt.ShieldJwtTokenService;
import com.shield.framework.security.token.uuid.ShieldUuidTokenService;
import lombok.RequiredArgsConstructor;
import net.dreamlu.mica.ip2region.core.Ip2regionSearcher;
import net.dreamlu.mica.redis.cache.MicaRedisCache;
import org.springframework.boot.autoconfigure.condition.*;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.*;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

/**
 * @description:
 * @Author Andy
 */
@ConditionalOnProperty(prefix = ShieldConstant.PROP_PREFIX ,name = "enabled",havingValue = "true",matchIfMissing = true)
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ShieldSecurityProperties.class)
@Import({ShieldSecurityConfig.class})
@ConditionalOnWebApplication
@RequiredArgsConstructor
public class ShieldAutoConfig {

    private final ShieldSecurityProperties properties;

    @Bean
    @Primary
    @ConditionalOnClass({MicaRedisCache.class,Ip2regionSearcher.class})
    @ConditionalOnMissingBean(ShieldTokenStore.class)
    @ConditionalOnProperty(prefix = ShieldConstant.PROP_PREFIX,name = "storeType",havingValue = ShieldConstant.StoreType.REDIS)
    public ShieldTokenStore getShieldRedisTokenStore(MicaRedisCache redisCache, Ip2regionSearcher searcher){
        return new ShieldRedisTokenStore(redisCache,searcher);
    }

    @ConditionalOnProperty(prefix = ShieldConstant.PROP_PREFIX,name = "storeType",havingValue = ShieldConstant.StoreType.DB)
    @Configuration(proxyBeanMethods = false)
    @EnableJpaRepositories(basePackageClasses = ShieldTokenRepository.class)
    @EntityScan(basePackageClasses = ShieldToken.class)
    public static class ShieldJpaConfig {}

    @Bean
    @ConditionalOnMissingBean(ShieldTokenStore.class)
    @ConditionalOnProperty(prefix = ShieldConstant.PROP_PREFIX,name = "storeType",havingValue = ShieldConstant.StoreType.DB)
    public ShieldTokenStore getShieldDbTokenStore(Ip2regionSearcher searcher, ShieldTokenRepository shieldTokenRepository){
        return new ShieldDbTokenStore(shieldTokenRepository,searcher);
    }

    @Bean
    @ConditionalOnMissingBean(ShieldTokenService.class)
    @ConditionalOnProperty(prefix = ShieldConstant.PROP_PREFIX,name = "tokenType",havingValue = ShieldConstant.TokenType.JWT)
    @Primary
    public ShieldTokenService shieldJwtTokenService(){
        return new ShieldJwtTokenService(properties);
    }

    @Bean
    @ConditionalOnMissingBean(ShieldTokenService.class)
    @ConditionalOnProperty(prefix = ShieldConstant.PROP_PREFIX,name = "tokenType",havingValue = ShieldConstant.TokenType.UUID)
    public ShieldTokenService shieldUuidTokenService(){
        return new ShieldUuidTokenService();
    }

    @Bean
    @ConditionalOnMissingBean(ShieldAuthHandler.class)
    public ShieldAuthHandler shieldAuthHandler(ShieldTokenService tokenService, ShieldTokenStore tokenStore){
        return new ShieldAuthHandler(tokenService,tokenStore,properties);
    }

    @Bean
    @ConditionalOnMissingBean(ShieldUserDetailsService.class)
    public ShieldUserDetailsService shieldUserDetailsService(){
        return new ShieldUserDetailsService();
    }

    @Bean
    @ConditionalOnMissingBean(ShieldAuthenticationTokenFilter.class)
    public ShieldAuthenticationTokenFilter shieldJwtAuthenticationTokenFilter(ShieldTokenService tokenService, ShieldTokenStore tokenStore, ShieldUserDetailsService detailsService){
        return new ShieldAuthenticationTokenFilter(tokenService,tokenStore,detailsService,properties);
    }


}
